namespace BadHabit.Factory.Reports
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Xml.XPath;
    using System.Xml.Xsl;

    public class BacklogReport : Report
    {
        /// <summary>
        /// Implements a Report class to generate a backlog report.
        /// </summary>
        /// <param name="factory"></param>
        public BacklogReport(FactoryLogic factory)
            : base(factory)
        {
        }

        /// <summary>
        /// The template type name.
        /// </summary>
        public override string TemplateTypeName
        {
            get
            {
                return "BacklogReport";
            }
        }

        /// <summary>
        /// Adjusts the dataset for XPS render.
        /// </summary>
        /// <param name="projectUId">The projectUId</param>
        /// <returns>The adjusted dataset</returns>
        public override System.Data.DataSet CreateDataSet()
        {
            return factory.RetriveProject(this.ProjectUId);
        }

        public override System.Data.DataSet AdjustDataSet(System.Data.DataSet report)
        {
            report = base.AdjustDataSet(report);

            Data.ProjectDataSet project = (Data.ProjectDataSet)report;

            project.Project.Columns.Add("BacklogEmmitionDateString", typeof(string));
            project.Project[0]["BacklogEmmitionDateString"] = DateTime.Now.ToLongDateString() + ", " + DateTime.Now.ToLongTimeString();

            project.Project.Columns.Add("EstimatedEndDateString", typeof(string));
            project.Project[0]["EstimatedEndDateString"] = project.Project[0].EstimatedEndDate.ToShortDateString();

            project.Sprint.Columns.Add("ExpirationDateString", typeof(string));
            project.Sprint.Columns.Add("StartDateString", typeof(string));
            project.Sprint.Columns.Add("ApprovalDateString", typeof(string));
            foreach (Data.ProjectDataSet.SprintRow r in project.Sprint)
            {
                r["StartDateString"] = MiniShortDateString(r.StartDate);
                if (!r.IsExpirationDateNull())
                {
                    r["ExpirationDateString"] = MiniShortDateString(r.ExpirationDate);
                }
             
                if (!r.IsApprovalDateNull())
                {
                    r["ApprovalDateString"] = MiniShortDateString(r.ApprovalDate);
                }
            }

            project.BacklogItem.Columns.Add("DeliverySprintNumber", typeof(short));
            project.BacklogItem.Columns.Add("DeliverySprintUId", typeof(string));
            foreach (Data.ProjectDataSet.BacklogItemRow item in project.BacklogItem)
            {
                if (item.DeliverySprint != null)
                {
                    item["DeliverySprintNumber"] = item.DeliverySprint.SprintNumber;
                    item["DeliverySprintUId"] = item.DeliverySprint.SprintUId;
                }
            }

            project.Project.Columns.Add("CurrentSprintUId", typeof(string));
            Data.ProjectDataSet.SprintRow currentSprint = project.Project[0].CurrentSprint;
            if (currentSprint != null)
            {
                project.Project[0]["CurrentSprintUId"] = currentSprint.SprintUId;
            }

            project.Project.Columns.Add("LastSprintUId", typeof(string));
            Data.ProjectDataSet.SprintRow lastSprint = project.Project[0].LastSprint;
            if (lastSprint != null)
            {
                project.Project[0]["LastSprintUId"] = lastSprint.SprintUId;
            }

            // read all project tasks
            Data.TaskDataSet tasks = factory.RetriveProjectTasks(project.Project[0].ProjectUId, -1);

            this.CalcSprintSpeed(project, tasks);
            this.CalcProjectSpeed(project, tasks);

            this.AddProjectIndicators(project);

            return report;
        }

        private void AddProjectIndicators(Data.ProjectDataSet project)
        {
            double budgetIndicator = 0.0;
            double qualityIndicator = 0.0;
            double velocityIndicator = 0.0;
            double deadlineIndicator = 0.0;
            double walkedIndicator = 0.0;

            try
            {
                Data.ProjectPerformanceDataSet.ProjectPerformanceRow ind = FactoryLogic.Current.RetriveProjectPerformanceIndicators(project.Project[0].ProjectUId);
                if (ind != null)
                {
                    budgetIndicator = ind.PctBudgetBurned;
                    qualityIndicator = ind.PctBugEffort;
                    velocityIndicator = ind.Velocity;
                    deadlineIndicator = ind.HoursAhead;
                    walkedIndicator = ind.PctWalked;
                }
            }
            catch
            {
            }

            project.Project.Columns.Add("BudgetIndicator", typeof(double));
            project.Project[0]["BudgetIndicator"] = budgetIndicator;
            project.Project.Columns.Add("QualityIndicator", typeof(double));
            project.Project[0]["QualityIndicator"] = qualityIndicator;
            project.Project.Columns.Add("VelocityIndicator", typeof(double));
            project.Project[0]["VelocityIndicator"] = velocityIndicator;
            project.Project.Columns.Add("DeadlineIndicator", typeof(double));
            project.Project[0]["DeadlineIndicator"] = deadlineIndicator;
            project.Project.Columns.Add("WalkedIndicator", typeof(double));
            project.Project[0]["WalkedIndicator"] = walkedIndicator;
        }

        private void CalcSprintSpeed(Data.ProjectDataSet project, Data.TaskDataSet tasks)
        {
            if (!project.Sprint.Columns.Contains("Speed"))
            {
                project.Sprint.Columns.Add("Speed", typeof(double));
            }

            foreach (Data.ProjectDataSet.SprintRow r in project.Sprint.Select(string.Empty, "SprintNumber"))
            {
                string doneFilter = "status=2 and StartDate >= '" + r.StartDate.ToShortDateString() + "' and FinishDate <= '" + r.ExpirationDate.ToShortDateString() + "'";

                string doneBacklogItemUIds = string.Empty;

                foreach (Data.ProjectDataSet.BacklogItemRow s in project.BacklogItem.Select(doneFilter))
                {
                    doneBacklogItemUIds = doneBacklogItemUIds + ",'" + s.BacklogItemUId + "'";
                }

                double sprintSize = 0;
                double.TryParse(project.BacklogItem.Compute("SUM(Size)", doneFilter).ToString(), out sprintSize);

                double sprintEffort = 0;
                if (doneBacklogItemUIds.Length > 0)
                {
                    double.TryParse(tasks.Task.Compute("SUM(ActualEffort)", "BacklogItemUId IN (" + doneBacklogItemUIds.Substring(1) + ")").ToString(), out sprintEffort);
                }

                if (sprintEffort > 0)
                {
                    r["Speed"] = sprintSize / sprintEffort;
                }
                else
                {
                    r["Speed"] = 0;
                }
            }
        }

        private void CalcProjectSpeed(Data.ProjectDataSet project, Data.TaskDataSet tasks)
        {
            if (!project.Project.Columns.Contains("Speed"))
            {
                project.Project.Columns.Add("Speed", typeof(double));
            }

            string doneFilter = "status=2";

            double size = 0;
            double.TryParse(project.BacklogItem.Compute("SUM(Size)", doneFilter).ToString(), out size);

            double effort = 0;
            double.TryParse(tasks.Task.Compute("SUM(ActualEffort)", string.Empty).ToString(), out effort);

            if (effort > 0)
            {
                project.Project[0]["Speed"] = size / effort;
            }
            else
            {
                project.Project[0]["Speed"] = 0;
            }
        }
    }
}
